// 版权所有2012 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 此文件定义操作数和相关操作。

package types

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/constant"
	"go/token"
)

// 操作数模式指定操作数的（寻址）模式。
type operandMode byte

const (
	invalid   operandMode = iota // 操作数无效
	novalue                      // 操作数不表示任何值（函数调用的结果，没有结果）
	builtin                      // 操作数是一个内置函数
	typexpr                      // 操作数是一种类型
	constant_                    // 操作数是一个常数；操作数的类型是基本类型
	variable                     // 操作数是一个可寻址变量
	mapindex                     // 操作数是映射索引表达式（在赋值的lhs上充当变量，在rhs上充当commaok）
	value                        // 操作数是一个计算值
	commaok                      // 类似于值，但操作数可以在逗号ok表达式中使用
	commaerr                     // 与commaok类似，但第二个值是错误，而不是布尔值
	cgofunc                      // 操作数是cgo函数
)

var operandModeString = [...]string{
	invalid:   "invalid operand",
	novalue:   "no value",
	builtin:   "built-in",
	typexpr:   "type",
	constant_: "constant",
	variable:  "variable",
	mapindex:  "map index expression",
	value:     "value",
	commaok:   "comma, ok expression",
	commaerr:  "comma, error expression",
	cgofunc:   "cgo function",
}

// 操作数表示类型检查期间的中间值。
// 操作数具有（寻址）模式，表达式计算为
// 操作数、操作数类型、常量值和id
// 用于内置函数。
// 操作数的零值是一个随时可用的无效操作数。
// None
type operand struct {
	mode operandMode
	expr ast.Expr
	typ  Type
	val  constant.Value
	id   builtinId
}

// Pos返回与x对应的表达式的位置。
// 如果x无效，则位置为token.NoPos。
// None
func (x *operand) Pos() token.Pos {
	// x、 如果x无效，则不能设置expr
	if x.expr == nil {
		return token.NoPos
	}
	return x.expr.Pos()
}

// 操作数字符串格式
// （由于类型系统的原因，并非所有“非类型”案例都会出现，
// 但它们在这里会自然脱落）
// None
// 模式格式
// None
// 无效的<expr>（<mode>）
// novalue<expr>（<mode>）
// 内置<expr>（<mode>）
// 类型xpr<expr>（<mode>）
// None
// 常数<expr>（<untyped kind><mode>）
// 常数<expr>（<mode>类型<typ>）
// 常数<expr>（<untyped kind><mode><val>）
// 常数<expr>（<mode><val>类型<typ>）
// None
// 变量<expr>（<untyped kind><mode>）
// 变量<expr>（<mode>类型<typ>）
// None
// mapindex<expr>（<untyped kind><mode>）
// mapindex<expr>（<mode>类型<typ>）
// None
// 值<expr>（<untyped kind><mode>）
// 值<expr>（<mode>类型<typ>）
// None
// 通信<expr>（<untyped kind><mode>）
// 通信<expr>（<mode>类型<typ>）
// None
// 通信<expr>（<untyped kind><mode>）
// 通信<expr>（<mode>类型<typ>）
// None
// cgofunc<expr>（<untyped kind><mode>）
// cgofunc<expr>（<mode>类型<typ>）
// None
func operandString(x *operand, qf Qualifier) string {
	var buf bytes.Buffer

	var expr string
	if x.expr != nil {
		expr = ExprString(x.expr)
	} else {
		switch x.mode {
		case builtin:
			expr = predeclaredFuncs[x.id].name
		case typexpr:
			expr = TypeString(x.typ, qf)
		case constant_:
			expr = x.val.String()
		}
	}

	// <expr>(
	if expr != "" {
		buf.WriteString(expr)
		buf.WriteString(" (")
	}

	// <untyped kind>
	hasType := false
	switch x.mode {
	case invalid, novalue, builtin, typexpr:
		// 无类型
	default:
		// 应该有一个类型，但要小心（打印时不要崩溃）
		if x.typ != nil {
			if isUntyped(x.typ) {
				buf.WriteString(x.typ.(*Basic).name)
				buf.WriteByte(' ')
				break
			}
			hasType = true
		}
	}

	// <mode>
	buf.WriteString(operandModeString[x.mode])

	// <val>
	if x.mode == constant_ {
		if s := x.val.String(); s != expr {
			buf.WriteByte(' ')
			buf.WriteString(s)
		}
	}

	// <typ>
	if hasType {
		if x.typ != Typ[Invalid] {
			var intro string
			switch {
			case isGeneric(x.typ):
				intro = " of generic type "
			case asTypeParam(x.typ) != nil:
				intro = " of type parameter type "
			default:
				intro = " of type "
			}
			buf.WriteString(intro)
			WriteType(&buf, x.typ, qf)
		} else {
			buf.WriteString(" with invalid type")
		}
	}

	// )
	if expr != "" {
		buf.WriteByte(')')
	}

	return buf.String()
}

func (x *operand) String() string {
	return operandString(x, nil)
}

// setConst将x设置为文字lit的非类型化常量。
func (x *operand) setConst(tok token.Token, lit string) {
	var kind BasicKind
	switch tok {
	case token.INT:
		kind = UntypedInt
	case token.FLOAT:
		kind = UntypedFloat
	case token.IMAG:
		kind = UntypedComplex
	case token.CHAR:
		kind = UntypedRune
	case token.STRING:
		kind = UntypedString
	default:
		unreachable()
	}

	val := constant.MakeFromLiteral(lit, tok, 0)
	if val.Kind() == constant.Unknown {
		x.mode = invalid
		x.typ = Typ[Invalid]
		return
	}
	x.mode = constant_
	x.typ = Typ[kind]
	x.val = val
}

// isNil报告x是否为nil值。
func (x *operand) isNil() bool {
	return x.mode == value && x.typ == Typ[UntypedNil]
}

// assignableTo报告x是否可分配给T类型的变量。如果
// 如果结果为false，并且提供了非nil原因，则可以将其设置为更高的值
// 故障的详细说明（结果！=“”）。返回的错误代码
// 仅当（第一个）结果为false时才有效。check参数可以是nil
// 如果通过导出的API调用调用assignableTo，即
// 方法已经过类型检查。
func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
	if x.mode == invalid || T == Typ[Invalid] {
		return true, 0 // 避免虚假错误
	}

	V := x.typ

	// x的类型与T相同
	if check.identical(V, T) {
		return true, 0
	}

	Vu := optype(V)
	Tu := optype(T)

	// x是一个非类型值，可由T类型的值表示。
	if isUntyped(Vu) {
		if t, ok := Tu.(*_Sum); ok {
			return t.is(func(t Type) bool {
				// TODO（gri）这可能更有效
				ok, _ := x.assignableTo(check, t, reason)
				return ok
			}), _IncompatibleAssign
		}
		newType, _, _ := check.implicitTypeAndValue(x, Tu)
		return newType != nil, _IncompatibleAssign
	}
	// Vu是打字的

	// x的V型和T型具有相同的底层类型
	// 并且V或T中至少有一个不是命名类型
	if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
		return true, 0
	}

	// T是一种接口类型，x实现T
	if Ti, ok := Tu.(*Interface); ok {
		if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
			if reason != nil {
				if wrongType != nil {
					if check.identical(m.typ, wrongType.typ) {
						*reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
					} else {
						*reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
					}

				} else {
					*reason = "missing method " + m.Name()
				}
			}
			return false, _InvalidIfaceAssign
		}
		return true, 0
	}

	// x为双向通道值，T为通道
	// 类型，x的类型V和T具有相同的元素类型，
	// 并且V或T中至少有一个不是命名类型
	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
		if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) {
			return !isNamed(V) || !isNamed(T), _InvalidChanAssign
		}
	}

	return false, _IncompatibleAssign
}
